/*
 * QuizWidget implementation.
 * Displays given options. Emits correct() or wrong()
 * signal depending on user's choice
 */

#include <QtGui>

#include "quizwidget.h"

#include <algorithm>

QuizWidget::QuizWidget(QWidget* parent) :
	QWidget(parent),
        tickImage(":images/images/tick-icon-64.png"),
        questionImage(":images/images/Button-Help-icon-256.png"),
        crossImage(":images/images/cross.png") {
        // user has not selected an answer yet
	selected = 0;

	// start small and grow outward
	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

        // show instructions for now.
        // replace with option to continue after user has answerd.
        doneButton = new QPushButton("Select the most correct option", this);
        doneButton->setEnabled(false);
        connect(doneButton, SIGNAL(clicked()), this, SIGNAL(done()));
        // also cause cleanup to happen when done button is pressed
        connect(doneButton, SIGNAL(clicked()), this, SLOT(cleanup()));
}

// configure the widget for the given question
void QuizWidget::setQuestion(QList<Phrase> p, Phrase a) {
    if (!p.contains(a)) {
        qDebug() << "Quiz: 'answer' was not in list of possible options" << endl;
        return;
    }

    phrases = p; // create a local copy of the phrase pointers
    answer = a; // answer is the first element
    answerText = phrases.at(0).getName(); // hack; to remove

    createButtons(); // create and add the buttons
    createLayout();
}

// create outer and inner layouts
void QuizWidget::createLayout() {
        /*
         * Add buttons to the layout manager.
         */
        // create the central layout from the list of option buttons.
        QLayout *layout = createOptionsLayout(/*phraseToButtonMap.values()*/buttonList);
        // create outer layout to give us some drawing room
        QHBoxLayout *outerLayout = new QHBoxLayout();
	outerLayout->addStretch();
	outerLayout->addLayout(layout);
        outerLayout->addStretch();
        // add done button to layout
        QVBoxLayout *doneLayout = new QVBoxLayout();
        QHBoxLayout *bottomLayout = new QHBoxLayout();
        bottomLayout->addStretch();
        bottomLayout->addWidget(doneButton);
        doneLayout->addLayout(outerLayout);
        doneLayout->addLayout(bottomLayout);
        setLayout(doneLayout);
}

// create the layout containing the buttons
QLayout* QuizWidget::createOptionsLayout(const QList<QAbstractButton*> options) {
	QVBoxLayout *layout = new QVBoxLayout();
        layout->addStretch();
	QListIterator<QAbstractButton*> it(options);
	while (it.hasNext()) {
		layout->addWidget(it.next());
	}
        layout->addStretch();
	return layout;
}

// instantiate the option buttons
void QuizWidget::createButtons() {
	// add a button for each phrase
        int i = 0;
        foreach(Phrase phrase, phrases) {
                // pass button index along
                QAbstractButton *button = createButton(phrase, i++);
                // add button to sequential list.
                // in this data structure, buttons are in the same
                // order as they appear on the GUI
                buttonList.append(button);
		// associate this button with the phrase. from now on,
		// we only need it to behave as a QAbstractButton
		// (it is already configured to show phrase)
                /*
                 * Note that the button order is lost at this point
                 */
                phraseToButtonMap.insert(phrase, button);
		// connect signals up
		connect(button, SIGNAL(clicked()), this, SLOT(optionClicked()));
	}
}

// create a button for this phrase.
// default implementation creates a QPushButton with the phrase
// content as its text
QAbstractButton* QuizWidget::createButton(Phrase phrase, int index) {
        return new QPushButton(phrase.getName());
}

void QuizWidget::reset() {
    // impossible to clear layout??
    phrases.clear();
    phraseToButtonMap.clear();
    selected = false;
    selectedCorrect = false;
    //delete layout();
}

// one of the available option buttons has been clicked. slot connected to button signals
void QuizWidget::optionClicked() {
	// disable the options
	disableButtons();

	// retrieve the source widget
	selected = qobject_cast<QAbstractButton*>(sender());
	// change background colour using stylesheets.
	// Palettes did not work.
	// we don't want gray text for the selected button
	selected->setStyleSheet("background-color: orange; color: black");
	// set up a timer. the answer will be revealed in 0.5 seconds
	timerId = startTimer(500);
}

// mark the user's answer
void QuizWidget::timerEvent(QTimerEvent *event)
{
    if (timerId == event->timerId())
    {
        // stop timer (single shot)
        killTimer(timerId);


        answerSelected();

        // show the 'done' button, allowing the user to end the quiz
        doneButton->setText("Continue");
        doneButton->setEnabled(true);
        // switch on the icon
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/images/images/Button-Next-icon-256.png"), QSize(), QIcon::Normal, QIcon::Off);
        doneButton->setIcon(icon);

        // look up the button which should have been pressed
        QAbstractButton* correctButton = phraseToButtonMap.value(answer);
        // compare to button which was actually pressed.
        selectedCorrect = (correctButton == selected);

        if (selectedCorrect)
        {
            qDebug() <<"correct answer";
            // style button
            correctAnswer(selected);
            // send signal
            emit correct();
        }
        else
        {
            // incorrect
            wrongAnswer(selected);
            qDebug() <<"incorrect answer";
            emit wrong();
            // reveal correct answer
            QAbstractButton* correctButton = phraseToButtonMap[answer];
            revealAnswer(correctButton);
        }
    } else {
        // throw to parent
        QWidget::timerEvent(event);
    }
}

void QuizWidget::correctAnswer (QAbstractButton* button) {
	// correct
	// light green background
        button->setStyleSheet("background-color: lightgreen; color: darkgreen;");
        update();
}

void QuizWidget::wrongAnswer (QAbstractButton* button) {
	// incorrect
	// red background
        button->setStyleSheet("background: red; color: black;");
	update();
}

void QuizWidget::revealAnswer (QAbstractButton* button) {
	button->setStyleSheet("color: white; background-color: blue");
	update();
}

void QuizWidget::disableButtons() {
	if (phraseToButtonMap.empty())
		return;
	
	// disable all the buttons
        QMapIterator<Phrase, QAbstractButton*> it(phraseToButtonMap);
	while (it.hasNext()) {
		it.next();
                it.value()->setDisabled(true);
	}
}

void QuizWidget::paintEvent(QPaintEvent *event) {
	QPainter p(this);
	if (0 != event) {
		// only draw tick/cross if an answer has been selected
		if (0 != selected) {
			// select appropriate image
			QImage* img = selectedCorrect ? &tickImage : &crossImage;
			// position the img to the right of the buttons
			int x = selected->x() + selected->width() + 5;
			int y = selected->y() - 4;
			p.drawImage(x, y, *img);

		}
                // draw question mark
                p.drawImage(QRect(1,1,48,48), questionImage);
                p.setFont(QFont("serif", 13, QFont::Bold, false));
                p.drawText(70, 30, "Quiz");
	}
}

QSize QuizWidget::sizeHint() const {
	// use layout's size hint as a starting point
	QSize size(layout()->sizeHint());
	// set width.
	// add about 100px to layout's preferred width
	// so there is painting room on the sides
	size.setWidth(layout()->sizeHint().width() + 100);
	return size;
}

// free option buttons
QuizWidget::~QuizWidget() {
	// free the button memory
        QMapIterator<Phrase, QAbstractButton*> it(phraseToButtonMap);
	while (it.hasNext()) {
		it.next();
		delete it.value();
	}
	phraseToButtonMap.clear();
}
